package procilege.lang;

import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;

import merisis.sense.SenseMaker;

import com.google.inject.Inject;
import com.google.inject.Injector;

import procilege.NoFoundNamespace;
import procilege.impl.NameImpl;

public class ScopeBlock {
	
	@Inject
	private SenseMaker nr;
	
	@Inject
	private Injector injector;

	private Map<String, String> prefixMap = new HashMap<String, String>();

	private Map<String, String> nsMap = new HashMap<String, String>();

	private ScopeBlock parent;

	private String defaultNamespaceURI;

	public String getDefaultNamespaceURI() {
		return defaultNamespaceURI;
	}

	public Map<String, String> getPrefixMap() {
		return prefixMap;
	}

	public synchronized void registerNamespace(String nsURI, String prefix) {

		if (nsURI == null)
			return;

		if (prefix == null)
			defaultNamespaceURI = nsURI;
		else {
			prefixMap.put(prefix, nsURI);
			nsMap.put(nsURI, prefix);
		}
	}

	public Name name(String prefix, String localpart) {

		String ns = findNamespaceURI(prefix);
		if (ns == null) {
			System.out.println("SCOPE: " + toDebugString());
			throw new NoFoundNamespace("unknown prefix: " + prefix);
		}

		return new NameImpl(nr.sense(new QName(ns, localpart)));
	}

	public ScopeBlock spawn() {

		ScopeBlock blk = new ScopeBlock();
		injector.injectMembers(blk);

		blk.parent = this;
		blk.defaultNamespaceURI = this.getDefaultNamespaceURI();

		return blk;
	}

	public String findNamespaceURI(String prefix) {

		if (prefix == null)
			return defaultNamespaceURI;

		String ns = prefixMap.get(prefix);
		if (ns != null)
			return ns;

		if (parent != null)
			return parent.findNamespaceURI(prefix);

		return null;
	}

	public String findCurrentPrefix(String nsURI) {

		if (nsURI == null)
			return null;

		if (nsURI.equals(defaultNamespaceURI))
			return null;

		String prefix = nsMap.get(nsURI);
		if (prefix != null)
			return prefix;

		if (parent != null)
			return parent.findCurrentPrefix(nsURI);

		return null;
	}

	public String toDebugString() {

		StringBuilder sb = new StringBuilder();

		if (parent != null) {
			sb.append('{');
			sb.append(parent.toDebugString());
			sb.append('}');
			sb.append(' ');
		}
		sb.append('"');
		sb.append(defaultNamespaceURI);
		sb.append('"');
		for (String px : prefixMap.keySet()) {
			sb.append(',');
			sb.append(px);
			sb.append(':');
			sb.append('"');
			sb.append(prefixMap.get(px));
			sb.append('"');
		}

		return sb.toString();
	}
}